package com.linhun.nickmao.demo;

import android.app.Activity;
import android.app.Application;
import android.os.Bundle;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;


import com.linhun.nickmao.demo.activitylifecycle.ActivityLifecycleCallbacksCompat;
import com.linhun.nickmao.demo.activitylifecycle.ApplicationHelper;

import java.util.Stack;

/**
 * Created by 冒秉文 on 2015/4/2.
 */
public class CrashHandler implements Thread.UncaughtExceptionHandler {

    private static final String TAG = "CrashHandler";

    private Application mContext;
    private static final CrashHandler INSTANCE = new CrashHandler();

    private Thread.UncaughtExceptionHandler mDefaultHandler;
    private Stack<Activity> mBackStack = new Stack<Activity>();
    /**
     * 标示是否正在执行uncaughtException方法,防止连环抛出异常导致uncaughtException重复执行
     */
    private boolean mBusying = false;

    /**
     * 定义Activity生命周期回调事件
     */
    private final ActivityLifecycleCallbacksCompat mCallback = new ActivityLifecycleCallbacksCompat() {
        @Override
        public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
            Log.d(TAG,activity.getClass().getSimpleName() + " has created");
            mBackStack.push(activity);
            Log.d(TAG,activity.getClass().getSimpleName() + " has push into stack");
        }

        @Override
        public void onActivityStarted(Activity activity) {
            Log.d(TAG,activity.getClass().getSimpleName() + " has started");
        }

        @Override
        public void onActivityResumed(Activity activity) {
            Log.d(TAG,activity.getClass().getSimpleName() + " has resumed");
        }

        @Override
        public void onActivityPaused(Activity activity) {
            Log.d(TAG,activity.getClass().getSimpleName() + " has paused");
        }

        @Override
        public void onActivityStopped(Activity activity) {
            Log.d(TAG,activity.getClass().getSimpleName() + " has stopped");
        }

        @Override
        public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
            Log.d(TAG,activity.getClass().getSimpleName() + " has SaveInstanceState");
        }

        @Override
        public void onActivityDestroyed(Activity activity) {
            Log.d(TAG,activity.getClass().getSimpleName() + " has destoryed");
            mBackStack.pop();
            Log.d(TAG,activity.getClass().getSimpleName() + " pop from stack");
        }
    };


    private CrashHandler(){}

    public static CrashHandler getInstance(){
        return INSTANCE;
    }


    public void init(Application app){
        mContext = app;
        mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
        Thread.setDefaultUncaughtExceptionHandler(this);

        //注册生命周期监听事件
        ApplicationHelper.registerActivityLifecycleCallbacks(app, mCallback);
    }

    @Override
    public void uncaughtException(Thread thread, Throwable throwable) {
        if(mBusying) {
            Log.d(TAG,"uncaughtException in executing");
            return;
        }
        //注销掉生命周期监听，防止重复从Stack中移除元素
        ApplicationHelper.unregisterActivityLifecycleCallbacks(mContext,mCallback);
        //获取异常信息
        try {
            final String exception = throwable.getMessage();

            new Thread() {
                @Override
                public void run() {
                    Looper.prepare();
                    Toast.makeText(mContext, "应用出现严重异常,即将退出:" + exception, Toast.LENGTH_SHORT).show();
                    Looper.loop();
                }
            }.start();


            synchronized (this) {
                mBusying = true;
                Log.d(TAG, "Enter lock");
                while (!mBackStack.isEmpty()) {
                    final Activity activity = mBackStack.pop();
                    activity.finish();
                    Log.d(TAG, activity.getClass().getSimpleName() + " finish by exception");
                }
                mBusying = false;
            }
            Log.d(TAG, "Leave lock");

            Thread.sleep(3000);

            //杀死进程 保证下次起来的Application不会是错误的
            android.os.Process.killProcess(android.os.Process.myPid());
            System.exit(1);

        }catch(Exception e){
            if(mDefaultHandler != null){
                mDefaultHandler.uncaughtException(thread,throwable);
            }
        }

    }
}
